#include <PDTType.h>

#include "assert.h"

PDTType PDTType::Int;
PDTType PDTType::Bool;
PDTType PDTType::Void;

PDTType::PDTType(PDTCodeGraph & CG) :
  PDTNode(CG)
{
}

NodeTypeEnum
PDTType::getType()
{
  if (this == &Int)
    return PDTNumVar_Em;
  if (this == &Bool)
    return PDTBoolVar_Em;
  if (this == &Void)
    return PDTNode_Em;
  assert(false);
  return PDTNode_Em;
}

stringstream&
PDTType::toString(stringstream& ss) const
{
  if (this == &Int)
    {
      ss << "Integer";
      return ss;
    }
  if (this == &Bool)
    {
      ss << "Boolean";
      return ss;
    }
  if (this == &Void)
    {
      ss << "Void";
      return ss;
    }
  assert(false);
  ss << " ";
  return ss;
}

PDTSet::PDTSet(PDTCodeGraph & CG, string aName, PDTType * eType) :
  PDTType(CG), name(aName)
{
  if (eType == NULL)
    return;

  eType->addParent(this);
  addChild(eType);
}

PDTType *
PDTSet::getElementType()
{
  if (children.size() == 0)
    return NULL;
  return dynamic_cast<PDTType*> (children[0]);
}

stringstream&
PDTSet::toString(stringstream& ss) const
{
  ss << "Set ";
  if (children.size() > 0)
    {
      ss << "of (";
      children[0]->toString(ss);
      ss << ") ";
    }
  ss << name << endl;

  return ss;
}

PDTIntRange::PDTIntRange(PDTCodeGraph & CG, string aName,
		PDTExp* aStart, PDTExp* aEnd) :
  PDTSet(CG, aName, &PDTType::Int), start(aStart), end(aEnd)
{
    start->addParent(this);
    addChild(start);

    end->addParent(this);
    addChild(end);
}

stringstream&
PDTIntRange::toString(stringstream& ss) const
{
  ss << "Range ";
  ss << name;
  ss << "from ";
  start->toString(ss);
  ss << " length ";
  end->toString(ss);
  return ss;
}

PDTSequence::PDTSequence(PDTCodeGraph & CG, string aName, PDTType * eType,
    PDTIntRange * aRange, PDTIntRange * aelRange, unsigned int aSize) :
  PDTSet(CG, aName, eType), range(aRange), elRange(aelRange), size(aSize)
{
}

unsigned int 
PDTSequence::getSize() const {
    return size;
}

stringstream&
PDTSequence::toString(stringstream& ss) const
{
  ss << "Sequence ";
  if (range)
    {
      range->toString(ss);
    }
  if (children.size() > 0)
    {
      ss << "of (";
      children[0]->toString(ss);
      ss << ") ";
    }
  ss << name << endl;

  return ss;
}

